﻿Imports System
Imports System.ComponentModel
Imports System.Runtime.Serialization
Imports System.Xml.Serialization
Imports Microsoft.VisualBasic

''' <summary>
''' Top level class for the entire event sourcing model
''' </summary>
''' <remarks>
''' This contains the AggregateDefinition, EventDefinition and ProjectionDefinition records that are used in the code
''' generation process
''' </remarks>
<Serializable()>
<DataContract(Name:=NameOf(EventSourcingModel))>
<XmlType("eventSourcingModel", AnonymousType:=False)>
Public NotInheritable Class EventSourcingModel
    Implements System.ComponentModel.INotifyPropertyChanged

    <DataMember(Name:=NameOf(Name))>
    Private ReadOnly m_name As String
    ''' <summary>
    ''' The unique name by which the event sourcing model is known
    ''' </summary>
    ''' <remarks>
    ''' This is used to refer to this model in code and also in the default filename when saving the model
    ''' </remarks>
    <XmlAttribute(AttributeName:="ModelName")>
    Public ReadOnly Property Name As String
        Get
            Return m_name
        End Get
    End Property

    <DataMember(Name:=NameOf(Description))>
    Private m_description As String
    ''' <summary>
    ''' The documentation description of the model represented by this event sourcing model
    ''' </summary>
    ''' <returns>
    ''' It is possible for an application to have multiple unconnected even t sourcing models
    ''' </returns>
    <XmlElement()>
    Public Property Description As String
        Get
            Return m_description
        End Get
        Set(value As String)
            If (value <> m_description) Then
                m_description = value
                OnPropertyChanged(NameOf(Description))
            End If
        End Set
    End Property

    Private m_aggregates As New System.Collections.Generic.Dictionary(Of String, AggregateModel)
    ''' <summary>
    ''' The set of aggregates belonging to this event sourcing model
    ''' </summary>
    Public ReadOnly Property Aggregates As System.Collections.Generic.Dictionary(Of String, AggregateModel)
        Get
            Return m_aggregates
        End Get
    End Property

    ''' <summary>
    ''' Add a new aggregate with the given name to the collection
    ''' </summary>
    ''' <param name="AggregateName">
    ''' The unique name of the aggregate to add
    ''' </param>
    ''' <remarks>
    ''' If the aggregate name is not unique then an exception is thrown
    ''' </remarks>
    Public Sub AddNewAggregate(ByVal AggregateName As String)
        If (m_aggregates.ContainsKey(AggregateName)) Then
            Throw New AggregateNameExistsException(AggregateName)
        Else
            m_aggregates.Add(AggregateName, New AggregateModel(AggregateName))
            'Raise an aggregate added event
            OnAggregateAdded(AggregateName)
            'And notify any UI 
            OnPropertyChanged(NameOf(Aggregates))
        End If
    End Sub

    Private Sub OnAggregateAdded(ByVal NewAggregateName As String)
        RaiseEvent AggregateAdded(Me, New AggregateModelEventArgs(NewAggregateName))
    End Sub
    Public Event AggregateAdded(ByVal sender As Object, ByVal e As AggregateModelEventArgs)

    Public Sub DeleteAggregate(ByVal AggregateName As String)
        If (m_aggregates.ContainsKey(AggregateName)) Then
            m_aggregates.Remove(AggregateName)
            'Raise an aggregate deleted event
            OnAggregateRemoved(AggregateName)
            'And notify any UI 
            OnPropertyChanged(NameOf(Aggregates))
        End If
    End Sub

    Private Sub OnAggregateRemoved(ByVal RemovedAggregateName As String)
        RaiseEvent AggregateRemoved(Me, New AggregateModelEventArgs(RemovedAggregateName))
    End Sub
    Public Event AggregateRemoved(ByVal sender As Object, ByVal e As AggregateModelEventArgs)

#Region "Property Change Notification"
    Private Sub OnPropertyChanged(ByVal propertyName As String)

        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))

    End Sub
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
#End Region

    ''' <summary>
    ''' Empty constructor for serialisation
    ''' </summary>
    Public Sub New()

    End Sub

    ''' <summary>
    ''' Create a new model with the given name
    ''' </summary>
    ''' <param name="modelName">
    ''' The unique name of this event sourcing model
    ''' </param>
    Public Sub New(ByVal modelName As String)
        m_name = modelName
    End Sub

    Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
        If (info IsNot Nothing) Then
            m_name = info.GetString(NameOf(Name))
            m_description = info.GetString(NameOf(Description))
        End If
    End Sub

End Class
